﻿using BarManager.Core.ApplicationService.Interfaces;
using BarManager.Core.BusinessRules.Interfaces.Validator;
using BarManager.Core.DomainModel;
using BarManager.Core.DomainService;
using BarManager.Core.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace BarManager.Core.ApplicationService
{
    public class ClienteService : BaseApplicationService<Cliente>, IClienteService
    {
        private IDomicilioRepository DomicilioRepository { get; set; }
        public ClienteService(IObjectContext context, IClienteRepository repository, IDomicilioRepository domicilioRepository, IClienteValidator validator)
            : base(context, repository, validator)
        {
            this.DomicilioRepository = domicilioRepository;
        }

        public override IEnumerable<string> Update(Cliente entity)
        {
            if (Validator.IsValid(entity, ValidatorType.Update))
            {
                using (var tx = UnitOfWork.StartTransaction())
                {
                    #region Actualizamos cabecera
                    Cliente cliente = BaseRepository.Get(x => x.Id == entity.Id);
                    cliente.Nombre = entity.Nombre;
                    cliente.Apellido = entity.Apellido;
                    cliente.Email = entity.Email;
                    cliente.Observaciones = entity.Observaciones;
                    cliente.Telefono1 = entity.Telefono1;
                    cliente.Telefono2 = entity.Telefono2;
                    #endregion

                    #region Actualizamos detalle
                    var list = DomicilioRepository.Find(x => x.ClienteId == entity.Id);

                    //- Agregamos o actualizamos items
                    foreach (var item in entity.DomicilioList)
                    {
                        //- Buscamos si existe el item en BD
                        var aux = list.FirstOrDefault(x => x.Id == item.Id);

                        //- Si existe y no son iguales actualiza
                        if (aux != null && !EqualsItems(aux, item)) UpdateDomicilio(aux, item);

                        //- Si es null es nuevo item
                        if (aux == null)
                        {
                            //- Seteamos a que orden pertenece el nuevo item
                            item.ClienteId = entity.Id;
                            DomicilioRepository.Add(item);
                        }
                    }

                    //- Eliminamos items que fueron quitados del detalle
                    foreach (var item in list)
                    {
                        //- Buscamos si existe el item en memoria
                        var aux = entity.DomicilioList.FirstOrDefault(x => x.Id == item.Id);

                        //- Si es null es un item a eliminar
                        if (aux == null)
                        {
                            item.Activo = false;
                            DomicilioRepository.Update(item);
                        }
                    }

                    #endregion

                    UnitOfWork.Commit();
                    tx.Complete();
                }
            }
            return Validator.BrokenRules();
        }

        public override Cliente Get(Expression<Func<Cliente, bool>> condition)
        {
            Cliente cliente = base.Get(condition);
            cliente.DomicilioList = cliente.DomicilioList.Where(x => x.Activo).ToList();
            return cliente;
        }

        public IEnumerable<Domicilio> GetAllDomiciliosByClienteId(int id)
        {
            return DomicilioRepository.Find(x => x.ClienteId == id && x.Activo);
        }

        #region Metodos Auxiliares
        private void UpdateDomicilio(Domicilio itemOld, Domicilio itemNew)
        {
            itemOld.Barrio = itemNew.Barrio;
            itemOld.Calle = itemNew.Calle;
            itemOld.Departamento = itemNew.Departamento;
            itemOld.EntreCalles = itemNew.EntreCalles;
            itemOld.Numero = itemNew.Numero;
            itemOld.Piso = itemNew.Piso;

            DomicilioRepository.Update(itemOld);
        }

        private bool EqualsItems(Domicilio itemA, Domicilio itemB)
        {
            return (itemA.Barrio == itemB.Barrio &&
                    itemA.Calle == itemB.Calle &&
                    itemA.Departamento == itemB.Departamento &&
                    itemA.EntreCalles == itemB.EntreCalles &&
                    itemA.Numero == itemB.Numero &&
                    itemA.Piso == itemB.Piso);
        }
        #endregion
    }
}
